/*
 * Copyright (c) China Telecom Cloud Technology Co., Ltd. 2024-2025. All rights reserved.
 */
#ifndef FS_STRATEGY_H
#define FS_STRATEGY_H

#include <fcntl.h>
#include <fstream>
#include <iostream>
#include <memory>
#include <mutex>
#include <sstream>
#include <string>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>

#include "Segment.h"
#include "Logger.h"


// TODO(yangxianpku: 2025.08.18): 改为运行时参数
#define SHM_PATH_LEN (15)         // /mnt/hugepages/共15个字符

// r 4, w 2, x 1
// user, group, other
#define USER_READ_WRITE (0644)    // 文件读写权限
#define INDEX_MOD 4096

/**
 *! @brief 文件系统类型
 *
 */
enum class FileSystem {
    THREEFS,     // 3FS
    POSIX,       // UNIX POSIX
    LUSTRE,      // LUSTRE
    BUTT
};



// KV Cache FMT
const std::string LAYOUT = ConfigLoader::get_config<std::string>(
                                ConfigLoader::EnvVars::LAYOUT, 
                                DEFAULT_LAYOUT
                            );



class FsStrategy {
public:
    /**
     *! @brief 创建FsStrategy对象，初始化成员
     *         根据共享内存文件获取共享内存大小
     * 
     * @param mountPath KV Cache文件存储路径
     * @param path      共享内存文件路径
     * @param addr      共享内存虚拟地址指针
     */
    FsStrategy(std::string mountPath, 
            std::string path, 
            void *addr
        );


    ~FsStrategy() = default;



    /**
     *! @brief  虚函数，从文件中读取KV Cache数据到Segment中
     * 
     * @param objId      KV Cache对象id
     * @param segment    存储读取后KV Cache数据的Segment
     * @param srcOffset  KV Cache存储文件的偏移量
     * @param dstOffset  Segment数据地址的偏移量
     * @param length     读取数据长度
     * 
     * @return int32_t   成功返货0否则返回具体错误码
     */
    // TODO(yangxianpku: 2025.08.21): objId 是如何来的？
    virtual int32_t get(const std::string &objId, 
                        const Segment &segment,
                        const uint64_t srcOffset, 
                        const uint64_t dstOffset,
                        const uint64_t length
                    ) noexcept = 0;



    /**
     *! @brief  虚函数，将Segment中中的数据存储到具体的文件中
     * 
     * @param objId      KV Cache对象id(可能是哈希)
     * @param segment    存储读取后KV Cache数据的Segment
     * @param srcOffset  KV Cache存储文件的偏移量
     * @param dstOffset  Segment数据地址的偏移量
     * @param length     读取数据长度
     * 
     * @return int32_t   成功返货0否则返回具体错误码
     */
    virtual int32_t put(const std::string &objId, 
                        const Segment &segment,
                        const uint64_t srcOffset, 
                        const uint64_t dstOffset,
                        const uint64_t length
                    ) noexcept = 0;



    /**
     *! @brief 删除（驱逐）特定的KV Cache对应的文件
     * 
     * @param objId  KV Cache对象id(可能是哈希)
     * 
     * @return int32_t 成功返货0否则返回具体错误码
     */
    virtual int32_t remove(const std::string &objId) noexcept = 0;


    /**
     *! @brief 判断某个对应的KV Cache文件是否存在
     * 
     * @param objId 
     * @return bool
     */
    virtual bool isExist(const std::string &objId) noexcept = 0;

protected:
    std::string  fsMountPath;       // 文件系统挂载目录(KV Cache文件存储目录)
    std::string  shmPath;           // 共享内存文件目录
    uint64_t     shmSize;           // 共享内存大小
    void*        shmAddr = nullptr; // 共享内存首地址


    /**
     *! @brief 根据共享内存文件读取信息获取共享内存大小
     * 
     * @param path 共享内存文件路径
     * @param size 返回共享内存大小
     * @return int32_t 成功返货0，否则返回错误码
     */
    int32_t getSharedMemorySize(const std::string path,
                             uint64_t &size) noexcept;


    std::string filePrefix = "kvcache_";  // KV Cache持久化文件前缀


    /**
     *! @brief 根据对象ID找到对应的路径
     * 
     * @param objId 
     * @return std::string 
     */
    std::string getFileDirPath(const std::string &objId);


    /**
     *! @brief 根据对象ID找到其完整存储路径:  getFileDirPath + kv缓存文件名
     * 
     * @param objId 
     * @return std::string 
     */
    // TODO(yangxianpku: 2025.08.21): 考虑文件名加上.kv/.cache/kvcache后缀
    // TODO(yangxianpku: 2025.08.21): 考虑加上模型名称
    std::string getFileFullPath(const std::string &objId);


    /**
     *! @brief 根据给定文件路径名创建文件并返回文件句柄
     * 
     * @param path  文件路径字符串表示
     * @param flags 创建标签
     * @param mode  权限
     * 
     * @return int32_t 返回文件描述符fd
     */
    int32_t createFileWithPath(const std::string &path, 
                            int32_t flags, mode_t mode);
};

#endif